﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;

namespace Components
{
    public abstract class WorkflowComponentBase:IComparable<WorkflowComponentBase>
    {
        public Guid ComponentID { get; set; }
        public string ComponentName { get; set; }
        public string ComponentCategory { get; set; }
        public WorkflowActivityType ActivityType { get; set; }
        public string ComponentIconName { get; set; }
        public string ComponentImageName { get; set; }
        public abstract InstructionBase Instruction { get; set; }
        public abstract ResultBase Output { get; set; }
        public bool Enabled { get; set; }
        public string OutputName { get; set; }
        public string ErrorName { get; set; }
        public double X { get; set; }
        public double Y { get; set; }
        public string Description { get; set; }
        [TypeConverter(typeof(DependencyConverter))]
        public List<Guid> Dependencies { get; set; }

        public WorkflowComponentBase()
        {
            this.ComponentID = Guid.NewGuid();
            this.ComponentName = "New Component";
            this.ComponentCategory = "Simple activity";
            this.ActivityType = WorkflowActivityType.Simple;
            this.ComponentIconName = "StopWatch.png";
            this.ComponentImageName = "StopWatch.png";
            this.Enabled = true;
            this.OutputName = string.Empty;
            this.ErrorName = string.Empty;
            this.X = 100;
            this.Y = 100;
            this.Description = string.Empty;
            this.Dependencies=new List<Guid>();
        }

        public WorkflowComponentBase Clone()
        {
            WorkflowComponentBase component = (WorkflowComponentBase)Activator.CreateInstance(this.GetType());
            PropertyInfo[] props = this.GetType().GetProperties();
            foreach (PropertyInfo prop in props)
            {
                if (prop.CanRead && prop.CanWrite)
                {
                    object propValue = prop.GetValue(this, null);
                    prop.SetValue(component, propValue, null);
                }
            }
            component.ComponentID = Guid.NewGuid();

            return component;
        }

        public virtual XElement Save()
        {
            XElement xe = new XElement(
                "Component",
                new XAttribute("Type", this.GetType().Name),
                new XAttribute("ComponentID", this.ComponentID.ToString()),
                new XAttribute("ComponentName", this.ComponentName),
                new XAttribute("ComponentCategory", this.ComponentCategory),
                new XAttribute("ActivityType", this.ActivityType),
                new XAttribute("ComponentIconName", this.ComponentIconName),
                new XAttribute("ComponentImageName", this.ComponentImageName),
                new XAttribute("Enabled", this.Enabled),
                new XAttribute("OutputName", this.OutputName),
                new XAttribute("ErrorName", this.ErrorName),
                new XAttribute("X", this.X),
                new XAttribute("Y", this.Y),
                new XAttribute("Description", this.Description),
                new XAttribute(
                    "Dependencies", new DependencyConverter().ConvertFrom(this.Dependencies).ToString()
                    ));

            XElement instructionElement = this.Instruction.Serialize();
            xe.Add(instructionElement);
            XElement outputElement = this.Output.Serialize();
            xe.Add(outputElement);

            return xe;
        }

        public virtual WorkflowComponentBase Instantiate(Type componentType, XElement xe)
        {
            WorkflowComponentBase component =(WorkflowComponentBase) Activator.CreateInstance(componentType);
            component.ComponentID = new Guid(xe.Attribute("ComponentID").Value);
            component.ComponentName = xe.Attribute("ComponentName").Value;
            component.ComponentCategory = xe.Attribute("ComponentCategory").Value;
            component.ActivityType =
                (WorkflowActivityType)
                Enum.Parse(typeof (WorkflowActivityType), xe.Attribute("ActivityType").Value, false);
            component.ComponentIconName = xe.Attribute("ComponentIconName").Value;
            component.ComponentImageName = xe.Attribute("ComponentImageName").Value;
            component.Enabled = bool.Parse(xe.Attribute("Enabled").Value);
            component.OutputName = xe.Attribute("OutputName").Value;
            component.ErrorName = xe.Attribute("ErrorName").Value;
            component.X = double.Parse(xe.Attribute("X").Value);
            component.Y = double.Parse(xe.Attribute("Y").Value);
            component.Description = xe.Attribute("Description").Value;
            component.Dependencies = (List<Guid>) new DependencyConverter().ConvertTo(
                                                      xe.Attribute("Dependencies").Value, typeof (List<Guid>));

            XElement instructionElement = xe.Element("Instruction");
            component.Instruction = this.Instruction.Instantiate(instructionElement);
            XElement outputElement = xe.Element("Output");
            component.Output = this.Output.Instantiate(outputElement);
            
            return component;
        }

        #region Implementation of IComparable<WorkflowComponentBase>
        public int CompareTo(WorkflowComponentBase other)
        {
            return this.ComponentName.CompareTo(other.ComponentName);
        }

        #endregion
    }
}
